#ifndef _Ring_QUEUE_HPP_
#define _Ring_QUEUE_HPP_

#include <iostream>
#include <vector>
#include <pthread.h>
#include "sem.hpp"

const int g_default_num = 5; // 环形队列默认个数

template <class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
        : _ring_queue(default_num),
          _num(default_num),
          c_step(0),
          p_step(0),
          _space_sem(default_num),
          _data_sem(0)
    {
        pthread_mutex_init(&clock, nullptr);
        pthread_mutex_init(&plock, nullptr);
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }
    void push(const T &in) // 生产者：关注空间资源
    {
        _space_sem.p(); // 先申请信号量 -> P操作（这样不用访问临界资源就分配好资源了）

        pthread_mutex_lock(&plock); 
        // 临界区：一定是竞争成功的生产者线程 -> 就一个
        _ring_queue[p_step++] = in;
        p_step %= _num; // p_step永远是可以存放的位置
        pthread_mutex_unlock(&plock);

        _data_sem.v();
    }
    void pop(T *out) // 消费者：关注数据资源 -> 对比生产者
    {
        _data_sem.p();

        pthread_mutex_lock(&clock);
        *out = _ring_queue[c_step++];
        c_step %= _num;
        pthread_mutex_unlock(&clock);

        _space_sem.v();
    }
    void debug()
    {
        std::cerr << "size: " << _ring_queue.size() << " num: " << _num << std::endl;
    }

protected:
    std::vector<T> _ring_queue;
    int _num; // 环形队列的数据个数
    int c_step; // 消费下标
    int p_step; // 生产下标
    Sem _space_sem;
    Sem _data_sem;
    pthread_mutex_t clock;
    pthread_mutex_t plock;
};

#endif